package cn.walls1717.juc.cas;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * ABA问题测试
 *
 * @author walls1717
 * @create 2022/12/12 14:46
 **/
@Slf4j
public class ABADemo {

    static AtomicInteger atomicInteger = new AtomicInteger(100);
    static AtomicStampedReference<Integer> asr = new AtomicStampedReference<>(100, 1);

    public static void main(String[] args) throws InterruptedException {
        // aba();
        new Thread(()->{
            log.info("A 1次版本号 -> " + asr.getStamp());

            try {
                TimeUnit.MILLISECONDS.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            asr.compareAndSet(100, 101, asr.getStamp(), asr.getStamp() + 1);
            log.info("A 2次版本号 -> " + asr.getStamp());

            asr.compareAndSet(101, 100, asr.getStamp(), asr.getStamp() + 1);
            log.info("A 3次版本号 -> " + asr.getStamp());

        }, "A").start();

        new Thread(()->{
            int stamp = asr.getStamp();
            log.info("B 1次版本号 -> " + stamp);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            boolean b = asr.compareAndSet(100, 2022, stamp, stamp + 1);
            log.info("B 是否修改成功 " + b + " 结果 " + asr.getReference());
        }, "B").start();
    }

    /**
     * 模拟aba问题
     *
     * @throws InterruptedException 。
     */
    private static void aba() throws InterruptedException {
        new Thread(()->{
            atomicInteger.compareAndSet(100, 101);
            try {
                TimeUnit.MILLISECONDS.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            atomicInteger.compareAndSet(101, 100);
        }, "t1").start();

        TimeUnit.MILLISECONDS.sleep(200);

        new Thread(()->{
            try {
                TimeUnit.MILLISECONDS.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            log.info(atomicInteger.compareAndSet(100, 2022) + "  " + atomicInteger.get());

        }, "t2").start();
    }
}
